﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KylinORM.Utils;

namespace KylinORM.Message.Lock
{
    /// <summary>
    /// 数据库并发管理
    /// </summary>
    public class LockManager
    {
        #region 内部属性

        /// <summary>
        /// 表示数据类型，比如类名
        /// </summary>
        private string ClassId { get; set; }
        /// <summary>
        /// 表示数据的标识或主键
        /// </summary>
        private string Pk { get; set; }
        /// <summary>
        /// 表示拥有锁的实体的表示，通常是用户ID或SessionID
        /// </summary>
        private string Owner { get; set; }

        #endregion

        #region 连接消息服务器

        private IMessageProvider client = MessageProvider.GetInstance();

        /// <summary>
        /// 锁标识符
        /// </summary>
        private string LockKey
        {
            get
            {
                return "KyORM:LockMgr:" + this.ClassId + ":" + this.Pk;
            }
        }

        #endregion

        #region 初始化锁管理器
        
        /// <summary>
        /// 初始化悲观离线锁
        /// </summary>
        /// <param name="classId">表示数据类型，比如类名</param>
        /// <param name="pk">表示数据的标识或主键</param>
        /// <param name="owner">表示拥有锁的实体的表示，通常是用户ID或SessionID</param>
        private LockManager(string classId, string pk, string owner)
        {
            this.ClassId = classId;
            this.Pk = pk;
            this.Owner = owner;
        }
        /// <summary>
        /// 初始化悲观离线锁
        /// </summary>
        /// <param name="classId">表示数据类型，比如类名</param>
        /// <param name="pk">表示数据的标识或主键</param>
        /// <param name="owner">表示拥有锁的实体的表示，通常是用户ID或SessionID</param>
        public static LockManager Define(string classId, string pk, string owner)
        {
            return new LockManager(classId, pk, owner);
        }
        #endregion

        /// <summary>
        /// 尝试进入锁定状态
        /// </summary>
        /// <returns></returns>
        public bool Enter()
        {
            return this.Enter(new TimeSpan(0, 10, 0));
        }
        /// <summary>
        /// 尝试进入锁定状态
        /// </summary>
        /// <param name="timeout">锁定时间</param>
        /// <returns></returns>
        public bool Enter(TimeSpan timeout)
        {
            bool result = client.SetNX(this.LockKey, Encoding.UTF8.GetBytes(this.Owner));
            if (result)
            {
                client.Expire(this.LockKey, timeout);
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 获取一个值，该值指示当前的锁定者；如果当前没有锁定者，则返回NULL
        /// </summary>
        public string HeldOwner
        {
            get
            {
                return client.Get<string>(this.LockKey);
            }
        }
        /// <summary>
        /// 退出锁定状态
        /// </summary>
        /// <returns></returns>
        public void Exit()
        {
            client.Del(this.LockKey);
        }
    }
}
